package org.fujene.index;

import java.io.IOException;

import org.fujene.communicate.repli.ReplicatePeerSystem;
import org.fujene.logging.LogParser;
import org.fujene.structure.Queue;
import org.msgpack.MessagePackObject;
import org.msgpack.object.NilType;
import org.msgpack.object.RawType;
import org.msgpack.rpc.Request;
import org.msgpack.rpc.Server;
import org.msgpack.rpc.loop.EventLoop;

/**
 * It works as server to index data, data structures are specified by
 * setting file or other node's setting on startup.
 * @author fujisaka_yusuke
 */
public class ReplicateIndexSystem{
	public boolean stopFlag;
	private ReplicatePeerSystem connector;
	private int contentTypes, supplementTypes;
	private int port;
	private Server server;

	public ReplicateIndexSystem(ReplicatePeerSystem peer, int content, int supplement, int port){
		this.connector = peer;
		this.contentTypes = content;
		this.supplementTypes = supplement;
		this.port = port;
	}

	// RPC
	public class IndexRPCHandler{
		// FIXME: If messagepack-rpc improves 
		public void index(Request req) throws Exception{
			MessagePackObject obj = req.getArguments();
			MessagePackObject[] args = obj.asArray();
			long ID;
			String[] content;
			String[] appendix;

			int requireLength = contentTypes + supplementTypes + 1;
			if(args.length < requireLength || !args[0].isIntegerType()){
				req.sendError(RawType.create("Error(index): Not efficient index word or ID"));
				LogParser.severe("Error(index): Not efficient index word or ID, " + requireLength
						+ " needs but there are " + args.length + ".");
			}
			ID = args[0].asLong();

			content = new String[contentTypes];
			appendix = new String[supplementTypes];
			for(int i = 0; i < content.length; i++)
				content[i] = args[i + 1].asString();
			for(int i = 0; i < appendix.length; i++)
				appendix[i] = args[i + 1 + content.length].asString();

			connector.setNewIndex(new Queue(content, appendix, ID));
			req.sendResult(NilType.create());
		}

		public void read(Request req){
			connector.readMemory();
			req.sendResult(NilType.create());
		}

		public void save(Request req){
			connector.saveMemory();
			req.sendResult(NilType.create());
		}

		public void stop(Request req){
			connector.setStopper(true);
			this.notifyAll();
			req.sendResult(NilType.create());
		}
	}

	public void initService(){
		EventLoop eventLoop = EventLoop.defaultEventLoop();
		try{
			server = new Server(eventLoop);
			server.serve(new IndexRPCHandler());
			server.listen(port);
			// eventLoop.join();
		}catch(IOException e){}
	}

	public void stopService(){
		server.close();
	}
	
	@Override
	protected void finalize() throws Throwable{
		if(server != null) server.close();
		super.finalize();
	}
}
